package com.ada.sm2;

import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.signers.SM2Signer;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.util.encoders.Hex;

import java.security.Security;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.security.KeyFactory;
import java.security.interfaces.ECPublicKey;
import java.security.interfaces.ECPrivateKey;
import java.security.spec.ECPrivateKeySpec;
import java.security.spec.ECPublicKeySpec;
import java.security.SecureRandom;

public class SM2SignatureExample {
    public static void main(String[] args) throws Exception {
        Security.addProvider(new BouncyCastleProvider());

        // Generate SM2 key pair
        AsymmetricCipherKeyPair keyPair = generateSM2KeyPair();

        String message = "Hello, SM2!";

        ECPrivateKeyParameters privateKey = (ECPrivateKeyParameters) keyPair.getPrivate();
        ECPublicKeyParameters publicKey = (ECPublicKeyParameters) keyPair.getPublic();


        // Sign message using SM2
        byte[] signature = signSM2(message.getBytes(), (ECPrivateKeyParameters) keyPair.getPrivate());

        // Verify the signature
        boolean verified = verifySM2(message.getBytes(), signature, (ECPublicKeyParameters) keyPair.getPublic());
        System.out.println("Message: " + message);
        System.out.println("Signature: " + Hex.toHexString(signature));
        System.out.println("Signature Verified: " + verified);

        byte[] encryptedData = encryptSM2(message.getBytes(), publicKey);

        byte[] decryptedData = decryptSM2(encryptedData, privateKey);
        System.out.println("Decrypted Text: " + new String(decryptedData));
    }

    // Generate SM2 key pair
    public static AsymmetricCipherKeyPair generateSM2KeyPair() {
        ECNamedCurveParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec("sm2p256v1");
        ECDomainParameters ecParams = new ECDomainParameters(
                ecSpec.getCurve(), ecSpec.getG(), ecSpec.getN(), ecSpec.getH());

        ECKeyGenerationParameters keyGenParams = new ECKeyGenerationParameters(ecParams, new SecureRandom());
        ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
        keyPairGenerator.init(keyGenParams);
        return keyPairGenerator.generateKeyPair();
    }

    // Sign using SM2
    public static byte[] signSM2(byte[] message, ECPrivateKeyParameters privateKey) throws CryptoException {
        SM2Signer signer = new SM2Signer();
        signer.init(true, privateKey);
        signer.update(message, 0, message.length);
        return signer.generateSignature();
    }

    // Verify SM2 signature
    public static boolean verifySM2(byte[] message, byte[] signature, ECPublicKeyParameters publicKey) {
        SM2Signer verifier = new SM2Signer();
        verifier.init(false, publicKey);
        verifier.update(message, 0, message.length);
        return verifier.verifySignature(signature);
    }


    public static byte[] decryptSM2(byte[] data, ECPrivateKeyParameters privateKey) throws Exception {
        SM2Engine engine = new SM2Engine();
        engine.init(false, privateKey);

        return engine.processBlock(data, 0, data.length);
    }

    public static byte[] encryptSM2(byte[] data, ECPublicKeyParameters publicKey) throws Exception {
        SM2Engine engine = new SM2Engine();
        engine.init(true, publicKey);

        return engine.processBlock(data, 0, data.length);
    }
}
